package com.wiscamp.ninechapters.tags.application.services;

import com.wiscamp.ninechapters.tags.application.assemblers.CourseAssembler;
import com.wiscamp.ninechapters.tags.application.dto.command.CreateCourseCommand;
import com.wiscamp.ninechapters.tags.application.dto.command.UpdateCourseCommand;
import com.wiscamp.ninechapters.tags.application.dto.vo.CourseVO;
import com.wiscamp.ninechapters.tags.domain.repositories.CourseRepository;
import com.wiscamp.ninechapters.tags.domain.services.CourseService;
import cube.ddd.application.BaseAppService;
import cube.ddd.application.command.DeleteCommand;
import cube.ddd.application.command.DisableCommand;
import cube.ddd.application.command.EnableCommand;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.common.query.PagedObjects;
import cube.ddd.common.query.PagedQuery;
import cube.ddd.utils.AppServiceUtils;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
public class CourseAppService extends BaseAppService {

    private final CourseRepository courseRepository;

    private final CourseService courseService;

    public CourseAppService(CourseRepository courseRepository, CourseService courseService) {
        this.courseRepository = courseRepository;
        this.courseService = courseService;
    }

    //region course
    @HandleServiceException
    public CourseVO getCourse(@Min(0) long courseId) {
        return AppServiceUtils.getById(courseId, courseService::getCourse,
                CourseAssembler.Instance::toCourseVO);
    }

    @HandleServiceException
    public CourseVO getCourseByCode(@NotBlank String courseCode) {
        return AppServiceUtils.getByText(courseCode, courseRepository::getCourseByCode,
                CourseAssembler.Instance::toCourseVO);
    }

    @HandleServiceException
    public Collection<CourseVO> getCoursesByName(@NotBlank String courseName) {
        return AppServiceUtils.getListByText(courseName, courseRepository::getCoursesByName,
                CourseAssembler.Instance::toCourseVO);
    }

    @HandleServiceException
    public Collection<CourseVO> getAvailableCourses() {
        return AppServiceUtils.getList(courseRepository::getAvailableCourses,
                CourseAssembler.Instance::toCourseVO);
    }

    @HandleServiceException
    public PagedObjects<CourseVO> getCoursesByQuery(@NotNull PagedQuery query) {
        var pagedEntities = courseRepository.getCoursesByQuery(query);
        return AppServiceUtils.convertPagedObjects(pagedEntities, CourseAssembler.Instance::toCourseVO);
    }

    @HandleServiceException
    public CourseVO createCourse(@NotNull CreateCourseCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), courseService::createCourse,
                CourseAssembler.Instance::toCourseVO,
                CourseAssembler.Instance::fromCreateCommand);
    }

    @HandleServiceException
    public CourseVO updateCourse(@NotNull UpdateCourseCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), courseService::updateCourse,
                CourseAssembler.Instance::toCourseVO,
                CourseAssembler.Instance::fromUpdateCommand);
    }

    @HandleServiceException
    public boolean deleteCourse(@NotNull DeleteCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), courseService::deleteCourse);
    }

    @HandleServiceException
    public boolean enableCourse(@NotNull EnableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), courseService::enableCourse);
    }

    @HandleServiceException
    public boolean disableCourse(@NotNull DisableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), courseService::disableCourse);
    }

    // endregion
}
